package com.nbufe.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nbufe.common.core.domain.R;
import com.nbufe.common.core.utils.StringUtils;
import com.nbufe.domain.ResponseResult;
import com.nbufe.domain.dto.ModifyFossiFuelInfoDto;
import com.nbufe.domain.dto.QueryFossiFuelDTO;
import com.nbufe.domain.entity.EmissionOrigin;
import com.nbufe.domain.entity.FossilFuel;
import com.nbufe.domain.entity.Material;
import com.nbufe.domain.entity.Process;
import com.nbufe.domain.form.QueryFossiFuelByIdForm;
import com.nbufe.domain.form.QueryFossiFuelForm;
import com.nbufe.domain.vo.*;
import com.nbufe.mapper.EmissionOriginMapper;
import com.nbufe.mapper.FossilFuelMapper;
import com.nbufe.mapper.MaterialMapper;
import com.nbufe.mapper.ProcessMapper;
import com.nbufe.service.FossilFuelService;
import com.nbufe.utils.BeanCopyUtils;
import com.nbufe.utils.HttpContextUtils;
import com.nbufe.utils.UnderUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (FossilFuel)表服务实现类
 *
 * @author LZH
 * @since 2023-04-01 10:10:33
 */
@Service("fossilFuelService")
public class FossilFuelServiceImpl extends ServiceImpl<FossilFuelMapper, FossilFuel> implements FossilFuelService {

    @Resource
    private MaterialMapper materialMapper;

    @Resource
    private EmissionOriginMapper emissionOriginMapper;

    @Resource
    private ProcessMapper processMapper;

    @Override
    public R calcActivityLevelByMonth(ActivityLevelVo vo) {
        //获取指定年指定月指定的化石燃料
        List<FossilFuel> fossilFuelList = getFossiFuelByYearMonth(vo.getFossiId(), vo.getYear(), vo.getMonth());

        for (FossilFuel fossilFuel : fossilFuelList) {
            //化石燃料的活动水平 = 平均低位发热量 * 化石燃料的消耗量
            BigDecimal aveFuel = BigDecimal.valueOf(fossilFuel.getAveFuel());
            BigDecimal consumer = BigDecimal.valueOf(fossilFuel.getConsumer());
            BigDecimal multiply = aveFuel.multiply(consumer);
            double activityLevel = multiply.doubleValue();

            //更新化石燃料的活动水平
            fossilFuel.setActivityLevel(activityLevel);
            updateById(fossilFuel);
        }

        return R.ok();
    }

    @Transactional
    @Override
    public R addFossiFuelConsumeInfo(AddFossiFuelConsumeVo vo) {
        Calendar calendar = Calendar.getInstance();
        Date date = new Date(System.currentTimeMillis());
        calendar.setTime(date);
        if (Objects.isNull(vo.getYear())) {
            vo.setYear(calendar.get(Calendar.YEAR));
        }
        if (Objects.isNull(vo.getMonth())) {
            vo.setMonth(calendar.get(Calendar.MONTH));
        }
        FossilFuel fossilFuel = BeanCopyUtils.copyBean(vo, FossilFuel.class);
        //保存化石燃料的基本消耗等信息
        save(fossilFuel);

        //更新化石燃料的活动水平
        ActivityLevelVo activityLevelVo = BeanCopyUtils.copyBean(vo, ActivityLevelVo.class);
        calcActivityLevelByMonth(activityLevelVo);
        //更新化石燃料的碳排放因子
        CalcEmissionFactorVo emissionFactorVo = BeanCopyUtils.copyBean(vo, CalcEmissionFactorVo.class);
        calcEmissionFactoryByMonth(emissionFactorVo);

        //更新化石燃料的CO2排放量
        CalCO2EmissionVO calCO2EmissionVO = BeanCopyUtils.copyBean(vo, CalCO2EmissionVO.class);
        calcCo2EmissionByMonth(calCO2EmissionVO);

        return R.ok();
    }

    private FossilFuel getTargetYearMonthFossiFuel(Integer year, Integer month, Integer fossiId) {
        LambdaQueryWrapper<FossilFuel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FossilFuel::getYear, year);
        queryWrapper.eq(FossilFuel::getMonth, month);
        queryWrapper.eq(FossilFuel::getFossiId, fossiId);
        return getOne(queryWrapper);
    }

    @Override
    public R calcEmissionFactoryByMonth(CalcEmissionFactorVo vo) {
        List<FossilFuel> fossilFuelList = getFossiFuelByYearMonth(vo.getFossiId(), vo.getYear(), vo.getMonth());
        for (FossilFuel fossilFuel : fossilFuelList) {
            //化石燃料的二氧化碳排放因子 = 单位热值含碳量 * 碳氧化率 * 44/12
            BigDecimal carbonFuel = BigDecimal.valueOf(fossilFuel.getCarbonFuel());
            BigDecimal oxidationRate = BigDecimal.valueOf(fossilFuel.getOxidationRate());
            double emissionFactor = carbonFuel.multiply(oxidationRate)
                    .multiply(BigDecimal.valueOf(0.0366667))
                    .multiply(BigDecimal.valueOf(0.001))
                    .setScale(4, RoundingMode.HALF_UP)
                    .doubleValue();

            //更新二氧化碳排放因子
            fossilFuel.setEmissionFactor(emissionFactor);
            updateById(fossilFuel);
        }
        return R.ok();
}

    @Override
    public R calcCo2EmissionByMonth(CalCO2EmissionVO vo) {
        List<FossilFuel> fossilFuelList = getFossiFuelByYearMonth(vo.getFossiId(), vo.getYear(), vo.getMonth());

        for (FossilFuel fossilFuel : fossilFuelList) {
            BigDecimal activityLeve = BigDecimal.valueOf(fossilFuel.getActivityLevel());
            BigDecimal emissionFactor = BigDecimal.valueOf(fossilFuel.getEmissionFactor());
            BigDecimal co2Emission = activityLeve.multiply(emissionFactor)
                    .setScale(2, RoundingMode.HALF_UP);

            fossilFuel.setCarbonEmission(co2Emission.doubleValue());
            updateById(fossilFuel);
        }
        return R.ok();
    }

    @Override
    public Double getTargetFossiFuelCarbonEmissionYear(GetFossiFuelCarbonEmissionYearVo vo) {
        LambdaQueryWrapper<FossilFuel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FossilFuel::getFossiId, vo.getFossiId());
        queryWrapper.eq(FossilFuel::getYear, vo.getYear());
        List<FossilFuel> fossilFuelList = list(queryWrapper);

        Double carbonEmission = 0.0;
        for (FossilFuel fossilFuel : fossilFuelList) {
            carbonEmission += fossilFuel.getCarbonEmission();
        }
        return carbonEmission;
    }

    @Override
    public Double getTotalCarbonEmissionByYear(Integer year) {
        LambdaQueryWrapper<FossilFuel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FossilFuel::getYear, year);
        List<FossilFuel> fossilFuelList = list(queryWrapper);

        return fossilFuelList.stream()
                .mapToDouble(FossilFuel::getCarbonEmission).sum();
    }

    @Override
    public Double getTotalCarbonEmissionByMonth(YearMonthVo vo) {
        LambdaQueryWrapper<FossilFuel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FossilFuel::getYear, vo.getYear());
        queryWrapper.eq(FossilFuel::getMonth, vo.getMonth());
        List<FossilFuel> fossilFuelList = list(queryWrapper);
        return fossilFuelList.stream()
                .mapToDouble(FossilFuel::getCarbonEmission).sum();
    }

    @Override
    public R pageList(QueryFossiFuelForm form) {
        Page<FossilFuel> page = new Page<>();
        page.setCurrent(form.getPageNum());
        page.setSize(form.getPageSize());

        QueryWrapper<FossilFuel> queryWrapper = new QueryWrapper<>();

        String tenantId = HttpContextUtils.getRequest().getHeader("tenant-id");
        queryWrapper.eq("tenant_id", Long.valueOf(tenantId));

        List<Material> materialList = null;
        if (StringUtils.hasText(form.getName())) {
            LambdaQueryWrapper<Material> materialLambdaQueryWrapper = new LambdaQueryWrapper<>();
            materialLambdaQueryWrapper.like(Material::getName, form.getName());
            materialLambdaQueryWrapper.eq(Material::getProduceStage, 1);
            materialList = materialMapper.selectList(materialLambdaQueryWrapper);
            if (Objects.isNull(materialList) || materialList.size() == 0) {
                return R.ok(new PageVo(0L, new ArrayList()));
            }
        }
        if (!Objects.isNull(materialList)) {
            List<Integer> collect = materialList.stream()
                    .map(Material::getId).collect(Collectors.toList());
            queryWrapper.in("fossi_id", collect);
        }
        queryWrapper.eq(Objects.nonNull(form.getYear()), "year", form.getYear());
        queryWrapper.eq(Objects.nonNull(form.getMonth()), "month", form.getMonth());

        List<Map<String, String>> sortArr = form.getSortArr();
        for (Map<String, String> map : sortArr) {
            String order = map.get("order");
            String prop = map.get("prop");
            prop = UnderUtil.camel2under(prop);
            if ("ascending".equals(order)) {
                queryWrapper.orderByAsc(prop);
            } else if ("descending".equals(order)) {
                queryWrapper.orderByDesc(prop);
            }
        }

        page(page, queryWrapper);
        List<FossilFuel> fossilFuelList = page.getRecords();

        //封装化石燃料名称
        List<QueryFossiFuelDTO> fossiFuelDTOS = BeanCopyUtils.copyBeanList(fossilFuelList, QueryFossiFuelDTO.class);
        for (QueryFossiFuelDTO fossiFuelDTO : fossiFuelDTOS) {
            Integer fossiId = fossiFuelDTO.getFossiId();
            Process process = processMapper.selectById(fossiFuelDTO.getProcessId());
            fossiFuelDTO.setProcessName(process != null ? process.getName() : "");
            EmissionOrigin emissionOrigin = emissionOriginMapper.selectById(fossiId);
            fossiFuelDTO.setName(emissionOrigin.getName());
        }

        PageVo pageVo = new PageVo(page.getTotal(), fossiFuelDTOS);
        return R.ok(pageVo);
    }

    @Override
    public List<Integer> listYears() {
        return baseMapper.selectAllYears();
    }

    @Override
    public ResponseResult deleteFossiFuel(List<Integer> fossiIds) {
        if (fossiIds.size() == 1) {
            removeById(fossiIds.get(0));
        } else {
            removeBatchByIds(fossiIds);
        }
        return ResponseResult.okResult();
    }

    @Override
    public QueryFossiFuelByIdForm queryFossiFuelInfoById(Integer id) {
        FossilFuel fossilFuel = getById(id);
        QueryFossiFuelByIdForm queryFossiFuelByIdForm = BeanCopyUtils.copyBean(fossilFuel, QueryFossiFuelByIdForm.class);

        Integer fossiId = fossilFuel.getFossiId();
        String name = materialMapper.selectById(fossiId).getName();

        queryFossiFuelByIdForm.setName(name);

        return queryFossiFuelByIdForm;
    }

    @Override
    public ResponseResult modifyFossiFuelInfo(ModifyFossiFuelInfoDto modifyFossiFuelInfoDto) {
        FossilFuel fossilFuel = BeanCopyUtils.copyBean(modifyFossiFuelInfoDto, FossilFuel.class);
        //更新碳排放数据
        //更新活动水平
        fossilFuel.setActivityLevel(fossilFuel.getAveFuel() * fossilFuel.getConsumer());
        //更新碳排放因子
        fossilFuel.setEmissionFactor(BigDecimal.valueOf(fossilFuel.getCarbonFuel() *
                fossilFuel.getOxidationRate() * 0.036667 * 0.001)
                .setScale(4, RoundingMode.UP).doubleValue());
        //更新碳排放数据
        fossilFuel.setCarbonEmission(BigDecimal.valueOf(fossilFuel.getConsumer() * fossilFuel.getEmissionFactor())
                .setScale(2, RoundingMode.UP).doubleValue());

        updateById(fossilFuel);
        return ResponseResult.okResult();
    }

    /**
     * 获取指定年指定月指定化石燃料的集合
     */
    private List<FossilFuel> getFossiFuelByYearMonth(int fossiId, int year, int month) {
        LambdaQueryWrapper<FossilFuel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FossilFuel::getYear, year);
        queryWrapper.eq(FossilFuel::getMonth, month);
        queryWrapper.eq(FossilFuel::getFossiId, fossiId);
        return list(queryWrapper);
    }
}

